﻿using System;
using System.Net;
using System.Net.Sockets;
using System.Threading.Tasks;
using System.Threading;


namespace GSE.Network.TCP
{
    public class TCPTransport : Transport
    {
        protected OptionContext optCtx;
        private Socket socket;
        protected Task recvTask;
        protected CancellationTokenSource keepAliveTaskCancellationTokenSource;
        protected Task keepAliveTask;
        protected string remoteAddress;
        protected Mutex sendMutex = new Mutex();
        protected Mutex readMutex = new Mutex();

        protected bool normalClosed = false;

        protected ILogger logger
        {
            get { return Logger.Default; }
        }

        public void ReceiveBufferSize(Int32 size)
        {
        }

        public Int32 ReceiveBufferSize()
        {
            return socket.ReceiveBufferSize;
        }

        public void SendBufferSize(Int32 size)
        {

        }

        public Int32 SendBufferSize()
        {
            return socket.SendBufferSize;
        }

        public TCPTransport(string remoteAddr, OptionContext optCtx)
        {
            var portions = remoteAddr.Split(':');
            if (portions.Length != 2)
            {
                throw new Exception("Invalid remote address: " + remoteAddr);
            }

            remoteAddress = remoteAddr;
            var ips = Dns.GetHostAddresses(portions[0]);
            socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            EndPoint ep = new IPEndPoint(ips[0], int.Parse(portions[1]));
            socket.Connect(ep);
            this.optCtx = optCtx;
        }

        /// <summary>
        /// 设置CancellationTokenSource后,当客户端在等待网络IO时,如果网络有错误则立即退出等待操作.
        /// </summary>
        /// <param name="cts">CancellationTokenSource</param>
        public void SetNetErrCancellationTokenSource(CancellationTokenSource cts)
        {

        }

        public void Close()
        {
            sendMutex.WaitOne();
            _close();
            sendMutex.ReleaseMutex();
        }

        public void Close(bool force)
        {
            if (!force)
            {
                sendMutex.WaitOne();
            }
            _close();
            if (!force)
            {
                sendMutex.WaitOne();
            }
        }

        protected void _close()
        {
            logger.Debug($"Closing client of {remoteAddress}.");
            socket.Close();
        }

        public void KeepAlive()
        {
            socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true);
        }

        public int SendData(byte[] data)
        {
            int n;
            try
            {
                sendMutex.WaitOne();
                n = socket.Send(data);

            }
            finally
            {
                sendMutex.ReleaseMutex();
            }
            return n;
        }

        public byte[] ReadData()
        {
            throw new Exception(" \"byte[] ReadData()\" not allowd for TCP transport.");
        }

        public int ReadData(byte[] buf)
        {
            int n;
            try
            {
                readMutex.WaitOne();
                n = socket.Receive(buf);
                if (n == 0 && buf.Length != 0)
                {
                    throw new RpcServiceConnectionException(remoteAddress);
                }

            }
            finally
            {
                readMutex.ReleaseMutex();
            }
            return n;
        }

        // 设置下次调用ReadData的超时时间.
        public void SetReadTimeout(int timeout)
        {
            socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, timeout);
        }

        public void Start()
        {

        }
    }


}
